package se.webbzon.boltzmann.game.object.portal;

import java.awt.Color;

import se.webbzon.boltzmann.environment.AbstractEnvironment;
import se.webbzon.boltzmann.game.environment.GameEnvironment;
import se.webbzon.boltzmann.game.event.AbstractGameEvent;
import se.webbzon.boltzmann.game.event.GameEventListener;
import se.webbzon.boltzmann.game.object.action.AbstractAction;
import se.webbzon.boltzmann.game.object.player.AbstractPlayerCharacter;
import se.webbzon.boltzmann.player.PlayerLocation;
import se.webbzon.boltzmann.resource.Resources;
import se.webbzon.oschi01.worldarea.WorldArea;
import se.webbzon.oschi01.worldeditor.DeflatableWorldObject;
import se.webbzon.oschi01.worldeditor.WorldObjectDeflation;
import se.webbzon.oschi01.worldobject.WorldObject;
import se.webbzon.oschi01.worldobject.appearance.Appearance3D;
import se.webbzon.oschi01.worldobject.appearance.CubeAppearance3D;
import se.webbzon.oschi01.worldobject.appearance.SimpleAppearance3D;

public class SavePortal extends AbstractPortal implements DeflatableWorldObject {
	
	// The name of the deflatable world object
	public static final String worldObjectName = "savePortal";
	
	// The rotation speed of this save portal
	private static final double rotationSpeed = Math.PI/60;
	
	// The shadow of this save portal
	private final SavePortalShadow shadow;
	
	// The abstract action of this save portal
	private final AbstractAction<SavePortal> action;
	
	// The number of steps passed since creation
	private int t;
	
	// The y-coordinate value of this save portal set by the user
	private double y;

	/*============================================================
	Public Methods
	============================================================*/
	
	/** Creates a new save portal. **/
	public SavePortal(AbstractEnvironment env, byte portalId) {
		super(	WorldObject.onCreate + WorldObject.onStep + 
				WorldObject.onDestroy, createAppearance(), env, "", portalId);
		super.setSize(16,16,2);
		action = new AbstractActionImpl(env);
		shadow = new SavePortalShadow(this);
	}
	
	/*============================================================
	Public Methods
	============================================================*/
	
	@Override public void onCreate(WorldArea world) {
		super.onCreate(world);
		if (!getEnvironment().isDebugMode()) {
			world.createInstance(action);
			shadow.launch(world);
		}
	}
	
	@Override public void onStep(WorldArea world) {
		t++;
		final double rotation = t * rotationSpeed;
		super.setRotation(0, 1, 0, rotation);
		super.setPosition(getX(), y + 4 + 2 * Math.sin(rotation), getZ());
	}

	@Override public void onDestroy(WorldArea world) {
		super.onDestroy(world);
		if (!getEnvironment().isDebugMode()) {
			world.destroyInstance(action);
			shadow.terminate(world);
		}
	}

	@Override public void setRotation(double x, double y, double z, double angle) {};

	@Override public void setSize(double width, double height, double depth) {};
	
	@Override public void setPosition(double x, double y, double z) {
		this.y = y;
		super.setPosition(x, y, z);
	}

	@Override public void spawn(AbstractPlayerCharacter player) {
		player.setPosition(getX(), getY() - getHeight()/2 + player.getHeight()/2, getZ());
		getWorld().destroyInstance(this);
	}
	
	@Override public String getName() {
		return worldObjectName;
	}

	@Override public WorldObjectDeflation getDeflation() {
		return new SavePortalDeflation(0,this);
	}
	
	/*============================================================
	Private Methods
	============================================================*/

	/** Creates the appearance of this save portal. **/
	private static final Appearance3D createAppearance() {
		SimpleAppearance3D appearance = new CubeAppearance3D();
		appearance.setTextureSet(Resources.getTextureSet("object_save_point"));
		return appearance;
	}
	
	/*============================================================
	Private Classes
	============================================================*/
	
	/** An implementation of an abstract action. **/
	private final class AbstractActionImpl extends AbstractAction<SavePortal> {

		public AbstractActionImpl(AbstractEnvironment env) {
			super(0, env, SavePortal.this, Color.green, false, 48);
		}

		@Override public void onActionBegin(SavePortal parent, AbstractPlayerCharacter player) {
			GameEnvironment genv = (GameEnvironment) getEnvironment();
			PlayerLocation location = player.getPlayer().getLocation().clone();
			location.setPortalId(getPortalId());
			SaveEvent event = new SaveEvent(genv,player.getPlayer().getInput(),getParent(),location);
			event.addListener(new GameEventListenerImpl(player));
			event.begin(getWorld());
		}
		
	}
	
	/** A game event listener used to block the input of a player. **/
	private static final class GameEventListenerImpl implements GameEventListener {

		// The player associated with this game event listener
		private final AbstractPlayerCharacter player;
		
		// The player blocker;
		private Object blocker;
		
		public GameEventListenerImpl(AbstractPlayerCharacter player) {
			this.player = player;
		}
		
		@Override public void onBegin(AbstractGameEvent event) {
			blocker = player.containBlocker();
		}

		@Override public void onEnd(AbstractGameEvent event) {
			player.releaseBlocker(blocker);
			event.removeListener(this);
		}
		
	}

}
